/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package syj.singletablemanager;

import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;

/**
 *
 * @author SYJ
 */
class BasicOperator
{
    private static final String CHARSET_NAME = "GB18030";
    private static final String SPLIT_SIGN = "\t";
    private File phyFile;
    private String ctrLine;
    private ArrayList<String> recordList;

    /**
     * 初始化{@code phyFile}、{@code ctrLine}，并可向{@code recordList}中插入数据
     *
     * @param phyFile 表格所对应的真实文件
     * @param createNewFile 若真实文件已经存在，是否覆盖并重建为空白文件
     * @throws FileNotFoundException 真实文件找不到时抛出
     */
    BasicOperator(File phyFile, boolean createNewFile) throws
            FileNotFoundException
    {
        this.phyFile = phyFile;
        recordList = new ArrayList<>();
        if (!createNewFile)
        {
            readFile();
        }
    }

    /**
     * 将真实文件写入缓存中的{@code recordList}
     *
     * @throws FileNotFoundException 真实文件找不到时抛出
     */
    final void readFile() throws FileNotFoundException
    {
        Scanner fileScanner = new Scanner(phyFile, CHARSET_NAME);
        if (fileScanner.hasNextLine())
        {
            setControlLine(fileScanner.nextLine());
            while (fileScanner.hasNextLine())
            {
                recordList.add(fileScanner.nextLine());
            }
        }
        fileScanner.close();
    }

    /**
     * 获得缓存中的控制行
     *
     * @return 缓存中的控制行
     */
    String getControlLine()
    {
        return ctrLine;
    }

    /**
     * 设置缓存中的控制行
     *
     * @param ctrLine 要写入的控制行
     */
    void setControlLine(String ctrLine)
    {
        this.ctrLine = ctrLine;
    }

    /**
     * 在表格的某列中查找匹配给定正则表达式的值，返回所有匹配值所在的记录行
     *
     * @param searchColumnIdx 查找的是第几列，从0开始计数
     * @param targetRegex 查找的值要匹配的正则表达式
     * @return 所有匹配值所在的那行记录
     */
    String[] select(int searchColumnIdx, String targetRegex)
    {
        ArrayList<String> matchedList = new ArrayList<>();
        for (int idx : searchRcdList(searchColumnIdx, targetRegex))
        {
            matchedList.add(recordList.get(idx));
        }
        return matchedList.toArray(new String[1]);
    }

    /**
     * 插入记录的基本操作
     *
     * @param values 待插入的那行新记录
     * @param autoNumber 新纪录前是否要插入自动编号
     */
    void insert(String[] values, boolean autoNumber)
    {
        String newValueLine = values[0];
        for (int i = 1; i < values.length; i++)
        {
            newValueLine += SPLIT_SIGN + values[i];
        }
        if (autoNumber)
        {
            int largestNo = 0;
            if (!recordList.isEmpty())
            {
                String lastLine = recordList.get(recordList.size() - 1);
                largestNo = Integer.parseInt(lastLine.substring(lastLine.lastIndexOf(SPLIT_SIGN) + 1));
            }
            newValueLine += SPLIT_SIGN + Integer.toString(largestNo + 1);
        }
        recordList.add(newValueLine);
    }

    /**
     * 修改记录，将某一列所有匹配给定正则表达式的值所在的行修改为{@code newValue}
     *
     * @param newValue 修改后的记录行
     * @param autoNumber 记录中是否有自动编号列
     * @param searchColumnIdx 要匹配的是第几列，从0开始计数
     * @param oldValue 修改前的值要匹配的正则表达式
     * @return 一共修改的行数
     */
    int update(String[] newValues, boolean autoNumber, int searchColumnIdx,
            String oldValue)
    {
        int[] updatingNos = searchRcdList(searchColumnIdx, oldValue);
        String newValueLine = newValues[0];
        for (int i = 1; i < newValues.length; i++)
        {
            newValueLine += SPLIT_SIGN + newValues[i];
        }
        for (int rcdListIdx : updatingNos)
        {
            if (autoNumber)
            {
                newValueLine += recordList.get(rcdListIdx).substring(recordList.get(rcdListIdx).lastIndexOf(SPLIT_SIGN));
            }
            recordList.set(rcdListIdx, newValueLine);
        }
        return updatingNos.length;
    }

    /**
     * 删除记录，将某一列所有匹配给定正则表达式的值所在的行删除
     *
     * @param searchColumnIdx 要匹配的是第几列，从0开始计数
     * @param targetRegex 删除的值必须匹配的正则表达式
     * @return 一共删除的记录行数
     */
    int delete(int searchColumnIdx, String targetRegex)
    {
        int[] updatingNos = searchRcdList(searchColumnIdx, targetRegex);
        for (int rcdListIdx : updatingNos)
        {
            recordList.remove(rcdListIdx);
        }
        return updatingNos.length;
    }

    /**
     * 按缓存完全重写表格的记录文件
     *
     * @throws FileNotFoundException
     * @throws UnsupportedEncodingException
     * @throws IOException
     */
    void writeBack() throws FileNotFoundException, UnsupportedEncodingException,
            IOException
    {
        FileOutputStream fos = new FileOutputStream(phyFile, false);
        OutputStreamWriter osw = new OutputStreamWriter(fos, CHARSET_NAME);
        PrintWriter pw = new PrintWriter(osw);
        pw.println(ctrLine);
        for (int i = 0; i < recordList.size(); i++)
        {
            pw.println(recordList.get(i));
        }
        pw.close();
        osw.close();
        fos.close();
    }

    /**
     * 在表格的某列中查找符合给定正则表达式的值，返回所有匹配值所在行在recordList中的下标
     *
     * @param searchColumnIdx 查找的是第几列，从0开始计数
     * @param regex 查找值要匹配的正则表达式
     * @return 返回所有匹配值所在行在recordList中的下标
     */
    private int[] searchRcdList(int searchColumnIdx, String regex)
    {
        ArrayList matchedList = new ArrayList();
        for (int i = 0; i < recordList.size(); i++)
        {
            if (recordList.get(i).split(SPLIT_SIGN)[searchColumnIdx].matches(regex))
            {
                matchedList.add(i);
            }
        }
        int[] results = new int[matchedList.size()];
        for (int i = 0; i < results.length; i++)
        {
            results[i] = (int)matchedList.get(i);
        }
        return results;
    }
}
